#include "MainForm.h"
#include "QmlClasses/QmlLoader.h"

#include <QDeclarativeEngine>
#include <QDeclarativeContext>
#include <QGraphicsObject>
#include <QDeclarativeItem>
#include <QVariant>

#include <QDebug>


//---------------------------------------------------------
MainForm::MainForm(QWidget *parent) :
    QDeclarativeView(parent),
    mTreeView(0),
    mLoader(*engine())
{
    init();
}


//---------------------------------------------------------
MainForm::MainForm(const QUrl &source, QWidget *parent) :
    QDeclarativeView(source, parent),
    mTreeView(0),
    mLoader(*engine())
{
    init();
}

//---------------------------------------------------------
void MainForm::close()
{
    hide();
    emit closed();
}

//---------------------------------------------------------
void MainForm::add(int key, const QString& value)
{
    elem.setKey(key);
    elem.setData(value);
    this->root.get_root()->tree_insert(elem);
}

//---------------------------------------------------------
void MainForm::remove(int key)
{
    qDebug() << "remove() key:" << key;

    Elem delel;
    delel.setKey(key);
    delel.setData("");
    root.get_root()->delete_element (delel);
}

//---------------------------------------------------------
Elem& MainForm::find(int key)
{
    Elem target;
    Node* last;
    target.setKey(key);
    target.setData("");
    return root.get_root()->search(target, last);

    //return elem.data();
}

//---------------------------------------------------------
void MainForm::nodeCreatedHandler(Node *node)
{
    QVariant father = 0,
            num = 0,
            qnode;

    QMetaObject::invokeMethod(
                mTreeView, "addNode",
                Q_RETURN_ARG(QVariant, qnode),
                Q_ARG(QVariant, father),
                Q_ARG(QVariant, num)
    );

    QDeclarativeItem *newNode = *(QDeclarativeItem**) qnode.constData();
    node->setQNode(newNode);
}

//---------------------------------------------------------
void MainForm::nodeChangedHandler(Node *node)
{
    if ( !node ) return;

    qDebug() << "[MainForm.cpp] node changed:" << node->getQNode()->objectName();

    int itemCount = *(int*) node->getQNode()->property("itemCount").constData();

    for ( int i = 1; i <= itemCount; i++ )
    {
        QString itemName = node->getQNode()->objectName() + QString("_item%1").arg(i);
        QDeclarativeItem *item = node->getQNode()->findChild<QDeclarativeItem*>(itemName);

        if ( i < node->getCount() )
        {
            if ( item == 0 )
            {
                item = mLoader.createItem(node->getQNode());
                int itemWidth = *(int*) node->getQNode()->property("itemWidth").constData();
                item->setX(itemWidth * (i - 1) + 2);
                item->setY(2);
                item->setObjectName(itemName);
                QObject::connect(item, SIGNAL(leftClick(int)), this, SLOT(itemClickedHandler(int)));
                QObject::connect(item, SIGNAL(rightClick(int)), this, SLOT(remove(int)));
            }
            int key = node->operator [](i).key();
            item->setProperty("key", key);
        }
        else if ( item )
        {
            qDebug() << "[MainForm.cpp] removing item" << item->objectName();
            item->deleteLater();
        }
    }
}

//---------------------------------------------------------
void MainForm::itemClickedHandler(int key)
{
    Elem& found = find(key);
    QString text = found.data();
    QDeclarativeItem *dataBlock = rootObject()->findChild<QDeclarativeItem*>("dataBlock");

    if ( dataBlock )
    {
        dataBlock->setProperty("value", text);
        dataBlock->setProperty("key", key);
    }
    else
        qDebug() << "cant find datablock";
}

//---------------------------------------------------------
void MainForm::fatherChangedHandler(Node *node)
{
    if ( !node ) return;

    qDebug() << "[MainForm.cpp] father changed for:" << node->getQNode()->objectName();

    if ( node->getFather() )
    {
        qDebug() << "[MainForm.qml] new father: " << node->getFather()->getQNode()->objectName();

        int parentIndex = node->getParentIndex();
        QVariant father = qVariantFromValue(node->getFather()->getQNode()),
                pointnum = parentIndex;

        QMetaObject::invokeMethod(
                    node->getQNode(), "setFather",
                    Q_ARG(QVariant, father),
                    Q_ARG(QVariant, pointnum)
        );
    }
    else
    {
        qDebug() << "[MainForm.qml] new father: 0";
        QMetaObject::invokeMethod(
                    node->getQNode(),
                    "disconnectFather"
        );
    }
}

//---------------------------------------------------------
void MainForm::replace(int key, const QString &value)
{
    find(key).setData(value);
}

//---------------------------------------------------------
void MainForm::nodeDestroyedHandler(Node *node)
{
    qDebug() << "[MainForm.cpp] node destroyed:" << node->getQNode()->objectName();

    QString linkName = node->getQNode()->objectName() + "_link";
    QDeclarativeItem *link = node->getQNode()->findChild<QDeclarativeItem*>(linkName);

    if ( link )
    {
        link->setProperty("a", 0);
        link->deleteLater();
        qDebug() << "[MainForm.cpp] link deleted:" << linkName;
    }
    else
        qDebug() << "[MainForm.cpp] can't find link:" << linkName;

    node->getQNode()->deleteLater();
}


//---------------------------------------------------------
void MainForm::init()
{
    rootContext()->setContextProperty("window", this);
    connect(engine(), SIGNAL(quit()), SLOT(close()));

    connect(&this->root, SIGNAL(nodeCreated(Node*)), SLOT(nodeCreatedHandler(Node*)));
    connect(&this->root, SIGNAL(nodeChanged(Node*)), SLOT(nodeChangedHandler(Node*)));
    connect(&this->root, SIGNAL(fatherChanged(Node*)), SLOT(fatherChangedHandler(Node*)));
    connect(&this->root, SIGNAL(nodeDestroyed(Node*)), SLOT(nodeDestroyedHandler(Node*)));

    QGraphicsObject *qroot = this->rootObject();
    qroot->setProperty("nodeSize", DEFAULT_NODE_COUNT);

    mTreeView = qroot->findChild<QDeclarativeItem*>("treeView");
    if (! mTreeView )
        qDebug() << "[MainForm.cpp] cant find TreeView";

    QDeclarativeItem *dataBlock = rootObject()->findChild<QDeclarativeItem*>("dataBlock");
    connect(dataBlock, SIGNAL(dataChanged(int, QString)), SLOT(replace(int,QString)));

    // инициализация статических данных
    Node::fail.invalidate();
    Node::fail.setKey(0);
    // инициализация корня
    Node* root_ptr = new Node(this->root);
    this->root.set_root (NULL, root_ptr);


    // connect signals
}
